/***************************************************************************
 *   Copyright (C) 2005 by xihe   *
 *   xihels@163.com                                                        *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/
#ifndef _LOGIN__H_
#define _LOGIN_H_
#include "Packet.h"

class QQClient;

/**
 * QQ登录请求包，格式为
 * 1. 头部
 * 2. 初始密钥，16字节
 * 3. 用户的密码密钥加密一个空串得到的16字节
 * 4. 36字节的固定内容，未知含义
 * 5. 登录状态，隐身登录还是什么，1字节
 * 6. 16字节固定内容，未知含义
 * 7. 登录令牌长度，1字节
 * 8. 登录令牌
 * 10. 未知1字节，0x40
 * 11. 后面段的个数，1字节，1个段9字节(猜测)
 * 12. 段，每次基本都是固定内容，未知含义
 * 13. 长度不足则全部填0直到符合登录包长度
 * 14. 尾部
 */

class LoginPacket : public OutPacket {
    public:
	LoginPacket(QQClient& cl) : OutPacket(cl, QQ_CMD_LOGIN) 
	{}
	int putLoginHead(uint8_t* buf) const;
	int putBody(uint8_t* buf) const;
};


/**
 * QQ登陆应答包
 * 000 字节是应答码，0表示登陆成功，1表示登陆重定向，5表示登录错误
 * 如果是0
 *	001-016字节是session key
 *	017-020字节是用户QQ号
 *	021-024字节是服务器探测到的用户IP
 *	025-026字节是服务器探测到的用户端口
 *	027-030字节是服务器自己的IP
 *	031-032字节是服务器的端口
 *	033-036字节是本次登陆时间，为什么要乘1000？因为这个时间乘以1000才对，-_-!...
 *	037-062是未知的26字节
 *	063-066字节是一个未知服务器1的ip
 *	067-068字节是一个未知服务器1的端口
 *	069-072是一个未知服务器2的ip
 *	073-074是一个未知服务器2的端口
 *	075-076是两个未知字节
 *	077-078是两个未知字节
 *	079-110是client key，这个key用在比如登录QQ家园之类的地方
 *	111-122是12个未知字节
 *	123-126是上次登陆的ip
 *	127-130是上次登陆的时间
 *	131-138是8个未知字节
 * 如果是1
 *	001-004字节是用户QQ号
 *	005-008字节是重定向到的服务器IP
 *	009-010字节是重定向到的服务器的端口
 * 如果是5
 *	一个错误消息
 */

class LoginReplyPacket : public InPacket {
    protected:
	LoginReplyPacket(const uint8_t* buf, int len);
    public:
	static InPacket* create(const uint8_t* buf, int len);
	void process(QQClient& client);

	const uint8_t* getClientKey() const { return clientKey; }
	const uint8_t* getSessionKey() const { return sessionKey; }
	const string getReplyMessage() const { return replyMessage; }
	uint32_t getLoginTime() const { return loginTime; }
	uint32_t getLastLoginTime() const { return lastLoginTime; }
	uint32_t getIp() const { return ip; }
	uint16_t getPort() const { return port; }
	uint32_t getServerIp() const { return serverIp; }
	uint16_t getServerPort() const { return serverPort; }
	uint32_t getLastLogIp() const { return lastLogIp; }
	uint32_t getRedirectIp() const { return redirectIp; }
	uint16_t getRedirectPort() const { return redirectPort; }
	uint8_t  getReplyCode() const { return replyCode; }
    private:
	uint8_t	clientKey[32];		// client key,用在比如登录QQ家园之类的地方
	uint8_t	sessionKey[QQ_KEY_LENGTH];	// 连接密钥
	string	replyMessage;		// 错误消息
	uint32_t    loginTime;		// 本次登陆时间
	uint32_t    lastLoginTime;		// 上次登陆的时间
	uint32_t    ip;			// 用户ip
	uint32_t    serverIp;		// 服务器ip
	uint32_t    lastLogIp;		// 上次登陆的ip
	uint32_t    redirectIp;		// 重定向到的服务器IP
	uint16_t    port;			// 用户端口
	uint16_t    serverPort;		// 服务器端口
	uint16_t    redirectPort;		// 重定向到的服务器端口
	uint8_t	replyCode;		// 回复码


};

/**
 * Logout请求包，这个包不需要服务器的应答，格式为
 * 1. 头部，序号不自动，指定为0xFFFF
 * 2. 用session key加密的password key
 * 3. 尾部
 */

class LogoutPacket : public OutPacket {
    public:
	LogoutPacket(QQClient& cl) : OutPacket(cl, QQ_CMD_LOGOUT) { sequence = 0xffff; }
	~LogoutPacket() {}
	int putBody(uint8_t* buf) const;
};

/**
 * Keep Alive包，这个包的格式是
 * 1. 头部
 * 2. 用户QQ号的字符串形式
 * 3. 尾部
 */
class KeepAlivePacket : public OutPacket {
    public:
	KeepAlivePacket(QQClient& cl) : OutPacket(cl, QQ_CMD_KEEP_ALIVE) {}
	int putBody(uint8_t* buf) const;
};

/** 请求一些操作需要的密钥，比如文件中转，视频也有可能 */
class RequestKeyPacket : public OutPacket {
    public:
	RequestKeyPacket(QQClient& cl, uint8_t _request) :
	    OutPacket(cl, QQ_CMD_REQUEST_KEY),
	    request(_request)
	{}
	int putBody(uint8_t* buf) const;
    private:
	uint8_t request;
};

class RequestKeyReplyPacket : public InPacket {
    protected:
	RequestKeyReplyPacket(const uint8_t* buf, int len) :
	    InPacket(buf, len){}
    public:
	uint8_t getReplyCode() const { return replyCode; }
	uint8_t getKeyType()   const { return keyType; }
	const uint8_t* getKey() const { return key; }
	const string& getToken() const { return token; }
    private:
	uint8_t	replyCode;
	uint8_t keyType;
	uint8_t key[16];
	string token;
};


#endif // _LOGIN_H_

